#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>  
#include <sys/wait.h>
#include <pthread.h>
#include "IPCAM_Export.h"
#include "Daemon_Common.h"

INT IsFileExist(CHAR *PATH)
{
	if (access(PATH, F_OK))	return FALSE;
	return TRUE; 
}
//no use
int Is_SPI_Falsh()
{
	FILE *fp = NULL;
	CHAR  Buf[255] ; 
	if(NULL == (fp =fopen(PATH_MOUNT_INFO ,FILE_MODE_READ)))
	{
		IPCAM_DEBUG("Open %s Error\n",PATH_MOUNT_INFO);
		return -1;
	}
	while(!feof(fp))
	{
		memset(Buf, 0, strlen(Buf));
		fgets(Buf, 254, fp);
		if (NULL != strstr(Buf, "upgrade"))  
		{
			fclose(fp);
			return 1;
		}
	}
	fclose(fp);
	return 0;	

}
//no use
INT IsMount(CHAR *pPathDev)
{
	FILE *fp       = NULL;
	CHAR  Buf[255] = {0};

	if (NULL == (fp=fopen(PATH_MOUNT_INFO, FILE_MODE_READ))){
		IPCAM_DEBUG("open %s Error", PATH_MOUNT_INFO);
		return TRUE;
	}

	while (!feof(fp))
	{
		memset(Buf, 0, strlen(Buf));
		fgets(Buf, 254, fp);
		if (NULL != strstr(Buf, pPathDev))
		{
			fclose(fp);
			return TRUE;
		}
	}

	fclose(fp);
	return FALSE;
}

CHAR *CompareVer(CHAR *Version1, CHAR *Version2)
{
	CHAR * Ver1Buf_1 = NULL;
	CHAR * Ver1Buf_2 = NULL;
	CHAR * Ver2Buf_1 = NULL;
	CHAR * Ver2Buf_2 = NULL;

	CHAR * tmp1 = NULL;
	CHAR * tmp2 = NULL;

	tmp1 = strstr(Version1, "V");
	tmp2 = strstr(Version2, "V");
	if((tmp1 == NULL) || (tmp2 == NULL)){
		return Version1;
	}
	Ver1Buf_1 = tmp1+1; 
	Ver2Buf_1 = tmp2+1;
	if      (atoi(Ver1Buf_1) > atoi(Ver2Buf_1))		  return Version1;
	else if (atoi(Ver1Buf_1) < atoi(Ver2Buf_1))	      return Version2;
	else
	{
		tmp1 = strstr(Ver1Buf_1, ".");
		tmp2 = strstr(Ver2Buf_1, ".");
		if((tmp1 == NULL) || (tmp2 == NULL)){
			return Version1;
		}
		Ver1Buf_2 = tmp1+1;
		Ver2Buf_2 = tmp2+1;
		if      (atoi(Ver1Buf_2) > atoi(Ver2Buf_2))   return Version1;
		else if (atoi(Ver1Buf_2) < atoi(Ver2Buf_2))   return Version2;
		else
		{
			tmp1 = strstr(Ver1Buf_2, ".");
			tmp2 = strstr(Ver2Buf_2, ".");
			if((tmp1 == NULL) || (tmp2 == NULL)){
				return Version1;
			}
			Ver1Buf_1 = tmp1+1;
			Ver2Buf_1 = tmp2+1;
			if (atoi(Ver1Buf_1) >= atoi(Ver2Buf_1))   return Version1;
			else				                      return Version2;
		}
	}
}

//no use
CHAR *CmpVersion(CHAR *SrcPath, CHAR *DestPath, CHAR *Type)
{
	DIR           *pSrcDir      = NULL;
	DIR           *pDestDir     = NULL;
	struct dirent *pSrcDirent   = NULL;
	struct dirent *pDestDirent  = NULL;
	CHAR          *CurVer       = NULL;
	CHAR          *SrcNewestVer  = NULL;
	CHAR          *NewestVer    = NULL;

	if(SrcPath == NULL || DestPath == NULL || Type == NULL)
		return NULL;
	
	if(false == sd_mount())
		return NULL;
	
	if (FALSE == IsFileExist(SrcPath))          
		return NULL;
	//判断卡上是不是有升级文件包
	IPCAM_DEBUG("compare version 1 \n");
	if (FALSE == IsFileExist(DestPath)){
		if(mkdir(DestPath, S_IRWXU|S_IRWXG|S_IRWXO)<0){
			perror(DestPath);
			return NULL;
		}
	}

	if (NULL == (pSrcDir=opendir(SrcPath)))     
		return NULL;
	if (NULL == (pDestDir=opendir(DestPath))) 
	{
		closedir(pSrcDir);
		return NULL;
	}
	while (NULL != (pSrcDirent=readdir(pSrcDir)))
	{
		if (NULL != (CurVer=(CHAR *)strstr(pSrcDirent->d_name, Type)))
		{
			CurVer=pSrcDirent->d_name;
			if (NULL == SrcNewestVer) 
			{
				SrcNewestVer = CurVer;
			}
			else 
			{
				SrcNewestVer = CompareVer(SrcNewestVer, CurVer);	
			}
		}	
	}
	//There's no update file on Src Dir
	if (NULL == SrcNewestVer)
	{
		closedir(pDestDir);
		closedir(pSrcDir);
		IPCAM_DEBUG("compare version  \n");
		return NULL;
	}

	NewestVer = SrcNewestVer;

	while (NULL != (pDestDirent=readdir(pDestDir)))
	{
		if (NULL != (CurVer=(CHAR *)strstr(pDestDirent->d_name, Type)))
		{
			CurVer=pDestDirent->d_name;
			NewestVer = CompareVer(SrcNewestVer, CurVer);
			IPCAM_DEBUG("NewestVer[%s] [%s]", NewestVer, CurVer);
			if (0 == strcasecmp(NewestVer, CurVer))	    
			{
				closedir(pDestDir);
				closedir(pSrcDir);
				//IPCAM_DEBUG("compare version  \n");
				return NULL;
			}
		}		
	}

	closedir(pDestDir);
	closedir(pSrcDir);
	IPCAM_DEBUG("compare vison end \n");
	return NewestVer;
}
 
CHAR *UpgradeApp(CHAR *SrcPath, CHAR *Type)
{
	DIR           *pSrcDir      = NULL;
	struct dirent *pSrcDirent   = NULL;
	CHAR          *CurVer       = NULL;
	CHAR          *SrcNewestVer = NULL;
	FILE          *fp  			= NULL;
	CHAR		  SrcVer[30];
	CHAR		  DstVer[30];
	CHAR 		  cmd[100];
	INT			  len;

	if(SrcPath == NULL || Type == NULL)
		return NULL;

	if(false == sd_mount())
		goto EXIT2;

	if (FALSE == IsFileExist(SrcPath))          
		goto EXIT2;

	//判断卡上是不是有升级文件包
	IPCAM_DEBUG("compare version 1");

	if (NULL == (pSrcDir=opendir(SrcPath)))     
		goto EXIT2;

	while (NULL != (pSrcDirent=readdir(pSrcDir)))
	{
		if (NULL != (CurVer=(CHAR *)strstr(pSrcDirent->d_name, Type)))
		{
			CurVer=pSrcDirent->d_name;
			if (NULL == SrcNewestVer) 
			{
				SrcNewestVer = CurVer;
			}
			else 
			{
				SrcNewestVer = CompareVer(SrcNewestVer, CurVer);	
			}
		}	
	}
	//There's no update file on Src Dir
	if (NULL == SrcNewestVer)
	{
		IPCAM_DEBUG("compare version  \n");
		goto EXIT;
	}

	if (FALSE == IsFileExist(PATH_TEMP)){
		if(mkdir(PATH_TEMP, S_IRWXU|S_IRWXG|S_IRWXO)<0){
			perror(PATH_TEMP);
			goto EXIT;
		}
	}
	memset(cmd,0,100);
	sprintf(cmd,"tar xvf %s/%s %s -C %s",SrcPath,SrcNewestVer,PATH_UPDATE_VERSION,PATH_TEMP);
	//IPCAM_DEBUG("cmd:%s",cmd);
	hi_system(cmd);
//SrcVer
	fp = fopen(PATH_VERSION,"r");
	if(fp == NULL)
	{
		IPCAM_DEBUG("%s is not exist\n",PATH_VERSION);
		goto EXIT;
	}
	memset(SrcVer,0,30);
	if((len = fread(SrcVer,1,30,fp)) < 1)
	{
		perror("read:");
		goto EXIT;
	}

	fclose(fp);
	
	SrcVer[len - 1] = '\0';  //去掉回车
	#if 0
	sprintf(ver,"%s.bin",SrcVer);
	#endif
	IPCAM_DEBUG("Src:%s",SrcVer);
//DstVer
	memset(cmd,0,100);
	sprintf(cmd,"%s/%s",PATH_TEMP,PATH_UPDATE_VERSION);
	fp = fopen(cmd,"r");
	if(fp == NULL)
	{
		IPCAM_DEBUG("%s is not exist\n",cmd);
		goto EXIT;
	}
	memset(DstVer,0,30);
	if((len = fread(DstVer,1,30,fp)) < 1)
	{
		perror("read:");
		goto EXIT;
	}

	fclose(fp);
	DstVer[len - 1] = '\0';  //去掉回车
	IPCAM_DEBUG("Dst:%s",DstVer);
//check
	if(strcasecmp(SrcVer, DstVer) < 0)
	{
		if(0 != hi_system("killall ipcam"))
			rt_system("killall ipcam");

		memset(cmd,0,100);
		sprintf(cmd,"tar xvf %s/%s -C /app",SrcPath,SrcNewestVer);
		IPCAM_DEBUG("cmd:%s",cmd);
		system(cmd);
		system("reboot -f");
		sleep(20);
		
	}

	memset(cmd,0,100);
	sprintf(cmd,"rm -rf %s",PATH_TEMP);
	rt_system(cmd);
	
	//_printd("SrcVer:%s\n",SrcNewestVer);
	IPCAM_DEBUG("compare vison end");

EXIT:
	closedir(pSrcDir);
EXIT2:
	sd_umount();
	return NULL;
	
//	return NewestVer;
}

BOOL Daemon_CheckProgram(CHAR * ProgramName)
{
	int    i = 0;
	CHAR   buf[512] = {0};
	INT    Fd      = -1;
	pid_t  pid     =  0;

	INT    nRet    = FALSE;
	DIR  * pDir    = NULL;
	struct dirent *pDirent = NULL;
	CHAR   filename[512]    = {0};
	CHAR   pProgramName[512] = {0};
	int    readbyte = 0;
	int    readtotalbyte = 0;
	if (NULL == (pDir=opendir("/proc"))){
		IPCAM_DEBUG("Open /proc Error!");
		return FALSE;
	}

	sprintf(pProgramName,"%s/",ProgramName);
	//_printd("%s\n",pProgramName);
	while (NULL != (pDirent=readdir(pDir))){
		if ((pid=atoi(pDirent->d_name))>0){
			memset(filename, 0, sizeof(filename));
			sprintf(filename, "/proc/%u/task/%u/cmdline", pid, pid);

			if (0>(Fd=open(filename, O_RDONLY)))
				continue;
			readtotalbyte = 0;	
			memset(buf, 0, sizeof(buf));
			for(i =0; i< 1024; i++)
			{
				if (0 >= (readbyte = read(Fd, buf+readtotalbyte, 512-readtotalbyte)))
				{
					break;
				}
				readtotalbyte += readbyte;
			}
			if(0 == readtotalbyte)
			{
				close(Fd);
				continue;
			}
			close(Fd);
			if(strstr(buf, "/bin/sh"))
			{
				if (strstr(buf+8, ProgramName))
				{
				
					if(NULL == strstr(buf, pProgramName))
					{
						nRet = TRUE;
						break;
					}
				
				}
			}
			else if(strstr(buf, ProgramName))
			{
				
				if(NULL == strstr(buf, pProgramName))
				{
					nRet = TRUE;
					break;
				}
				
			}
		}
	}
	closedir(pDir);

	return nRet;
}


/*
   函数使用说明：
   返回值：
   0 ：正常结束
   -1：输入命令无效
   -2：调用 popen失败
   -3：调用 pclose失败
   -4: 子进程是因为信号而结束
   -5: 子进程处于暂停执行
   -6: 命令运行失败
 */
int hi_system(char *cmd)
{
#if 0
	char result_buf[1024]={0}, command[1024]={0};
	int rc = 0;                 
	FILE *fp = NULL;

	if (NULL == cmd)
	{
		IPCAM_DEBUG("\r Parameter is invalid.");
		rc = -1;
		goto RET;
	}
	//_printd("hi_system cmd:%s\n",cmd);
	/*将要执行的命令写入buf*/
	snprintf(command, sizeof(command), cmd);
	/*执行预先设定的命令，并读出该命令的标准输出*/
	fp = popen(strcat(command," 2>&1"), "r");/* 把标准错误也映射到标准输出上 */
	if(NULL == fp)
	{
		IPCAM_DEBUG("popen fail");
		perror("erron:");
		rc = -2;
		goto RET;
	}
	while(fgets(result_buf, sizeof(result_buf), fp) != NULL)
	{        
		//为了下面输出好看些，把命令返回的换行符去掉
		if('\n' == result_buf[strlen(result_buf)-1])
		{
			result_buf[strlen(result_buf)-1] = '\0';
		}
		//IPCAM_DEBUG("output :%s", result_buf);        
	}

	/*等待命令执行完毕并关闭管道及文件指针*/
	rc = pclose(fp);
	if(rc == -1)         //pclose出错
	{
		IPCAM_DEBUG("pclose fail.");
		perror("erron:");	
		rc = -3;
		goto RET;
	}
	if(WIFEXITED(rc)) //如果子进程正常结束则为非0值
	{
		rc = WEXITSTATUS(rc);   //取得子进程exit()返回的结束代码
		if(rc == 127)
		{
			IPCAM_DEBUG("command run fail.");
			perror("erron:"); //命令运行失败  
			rc = -6;
		}
		else
		{
			IPCAM_DEBUG("normal termination, exit status = %d", rc); 
			rc = 0;
		}		
	}
	else if(WIFSIGNALED(rc))//如果子进程是因为信号而结束则此宏值为真
	{
		IPCAM_DEBUG("abnormal termination,signal number =%d", WTERMSIG(rc)); //取得子进程因信号而中止的信号值
		rc = -4;
	}
	else if(WIFSTOPPED(rc))//如果子进程处于暂停执行情况则此宏值为真
	{
		IPCAM_DEBUG("process stopped, signal number =%d", WSTOPSIG(rc)); //取得引发子进程暂停的信号值
		rc = -5;
	}
RET:
	if(rc != 0)
	{
		IPCAM_DEBUG("rc = %d",rc);
	}
	return rc;
#endif
}

int GetPidByName(char* task_name)
{
	CHAR   buf[64] = {0};
	INT    Fd      = -1;
	pid_t  pid     =  0;

	INT    nRet    = FALSE;
	DIR  * pDir    = NULL;
	struct dirent *pDirent = NULL;
	CHAR   filename[100]    = {0};
	CHAR   pProgramName[64] = {0};
	INT    i,j;
	
	if (NULL == (pDir=opendir("/proc"))){
		IPCAM_DEBUG("Open /proc Error!");
		return FALSE;
	}

	sprintf(pProgramName,"%s/",task_name);
//	_printd("%s\n",pProgramName);
	while (NULL != (pDirent=readdir(pDir))){
		if ((pid=atoi(pDirent->d_name))>0){
			memset(filename, 0, sizeof(filename));
			sprintf(filename, "/proc/%u/task/%u/cmdline", pid, pid);

			if (0>(Fd=open(filename, O_RDONLY)))
				continue;

			memset(buf, 0, sizeof(buf));
			if (0 >= (j=read(Fd, buf, sizeof(buf)))){
				close(Fd);
				continue;
			}
			close(Fd);
		//	_printd("filename:%s\n",filename);
			for(i = 0 ;i<j;i++)
			{
			//	_printd("%c,",buf[i]);
				if(i != j-1 && buf[i]==0)
					buf[i]=0xff;
			}
			//_printd("\n");
			if (strstr(buf, task_name)){
				if(NULL == strstr(buf, pProgramName))
				{
					nRet = TRUE;
					break;
				}
				
			}
		}
	}
	closedir(pDir);

	if(nRet == TRUE)
		return (int)pid;
	else
		return -1;
}
FILE * connect_sys(const char* cmd)
{	
	char result_buf[1024]={0}, command[1024]={0};
	int rc = 0;                 
	FILE *fp = NULL;

	if (NULL == cmd)
	{
		IPCAM_DEBUG("\r Parameter is invalid.");
		rc = -1;
		return NULL;
	}
	//_printd("hi_system cmd:%s\n",cmd);
	/*将要执行的命令写入buf*/
	snprintf(command, sizeof(command), cmd);
	/*执行预先设定的命令，并读出该命令的标准输出*/
	fp = popen(strcat(command," 2>&1"), "r");/* 把标准错误也映射到标准输出上 */
	return fp;
}
//static pthread_mutex_t  SystemMutex = PTHREAD_MUTEX_INITIALIZER;
void rt_system(const char* cmd)
{
	if(cmd == NULL || strlen(cmd) > 100)
		return;
	hi_system(cmd);
}